home *** CD-ROM | disk | FTP | other *** search
/ Multimedia Jumpstart / Multimedia Microsoft Jumpstart Version 1.1a (Microsoft).BIN / develpmt / sdk / vfw11.win / vfwdk / acmapp.c_ / acmapp.bin
Encoding:
Text File  |  1993-11-19  |  53.8 KB  |  1,947 lines

  1. //==========================================================================;
  2. //
  3. //  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4. //  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5. //  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6. //  PURPOSE.
  7. //
  8. //  Copyright (c) 1992, 1993  Microsoft Corporation.  All Rights Reserved.
  9. //
  10. //--------------------------------------------------------------------------;
  11. //
  12. //  acmapp.c
  13. //
  14. //  Description:
  15. //      This is a sample application that demonstrates how to use the 
  16. //      Audio Compression Manager API's in Windows. This application is
  17. //      also useful as an ACM driver test.
  18. //
  19. //==========================================================================;
  20.  
  21. #include <windows.h>
  22. #include <windowsx.h>
  23. #include <mmsystem.h>
  24. #include <commdlg.h>
  25. #ifndef WIN32
  26. #include <shellapi.h>
  27. #endif 
  28. #include <stdarg.h>
  29. #include <memory.h>
  30. #include <mmreg.h>
  31. #include <msacm.h>
  32.  
  33. #include "appport.h"
  34. #include "acmapp.h"
  35.  
  36. #include "debug.h"
  37.  
  38.  
  39. //
  40. //  globals, no less
  41. //
  42. HINSTANCE       ghinst;
  43. BOOL            gfAcmAvailable;
  44. UINT            gfuAppOptions       = APP_OPTIONSF_AUTOOPEN;
  45. HFONT           ghfontApp;
  46. HACMDRIVERID    ghadidNotify;
  47.  
  48. UINT            guWaveInId          = (UINT)WAVE_MAPPER;
  49. UINT            guWaveOutId         = (UINT)WAVE_MAPPER;
  50.  
  51. TCHAR           gszNull[]           = TEXT("");
  52. TCHAR           gszAppProfile[]     = TEXT("acmapp.ini");
  53. TCHAR           gszYes[]            = TEXT("Yes");
  54. TCHAR           gszNo[]             = TEXT("No");
  55.  
  56. TCHAR           gszAppName[APP_MAX_APP_NAME_CHARS];
  57. TCHAR           gszFileUntitled[APP_MAX_FILE_TITLE_CHARS];
  58.  
  59. TCHAR           gszInitialDirOpen[APP_MAX_FILE_PATH_CHARS];
  60. TCHAR           gszInitialDirSave[APP_MAX_FILE_PATH_CHARS];
  61.  
  62. TCHAR           gszLastSaveFile[APP_MAX_FILE_PATH_CHARS];
  63.  
  64. ACMAPPFILEDESC  gaafd;
  65.  
  66.  
  67. //==========================================================================;
  68. //
  69. //  Application helper functions
  70. //
  71. //
  72. //==========================================================================;
  73.  
  74. //--------------------------------------------------------------------------;
  75. //
  76. //  int AppMsgBox
  77. //
  78. //  Description:
  79. //      This function displays a message for the application in a standard
  80. //      message box.
  81. //
  82. //      Note that this function takes any valid argument list that can
  83. //      be passed to wsprintf. Because of this, the application must
  84. //      remember to cast near string pointers to FAR when built for Win 16.
  85. //      You will get a nice GP fault if you do not cast them correctly.
  86. //
  87. //  Arguments:
  88. //      HWND hwnd: Handle to parent window for message box holding the
  89. //      message.
  90. //
  91. //      UINT fuStyle: Style flags for MessageBox().
  92. //
  93. //      PTSTR pszFormat: Format string used for wvsprintf().
  94. //
  95. //  Return (int):
  96. //      The return value is the result of MessageBox() function.
  97. //
  98. //--------------------------------------------------------------------------;
  99.  
  100. int FNCGLOBAL AppMsgBox
  101. (
  102.     HWND                    hwnd,
  103.     UINT                    fuStyle,
  104.     PTSTR                   pszFormat,
  105.     ...
  106. )
  107. {
  108.     va_list     va;
  109.     TCHAR       ach[1024];
  110.     int         n;
  111.  
  112.     //
  113.     //  format and display the message..
  114.     //
  115.     va_start(va, pszFormat);
  116.     wvsprintf(ach, pszFormat, (LPSTR)va);
  117.     va_end(va);
  118.  
  119.     n = MessageBox(hwnd, ach, gszAppName, fuStyle);
  120.  
  121.     return (n);
  122. } // AppMsgBox()
  123.  
  124.  
  125. //--------------------------------------------------------------------------;
  126. //
  127. //  int AppMsgBoxId
  128. //
  129. //  Description:
  130. //      This function displays a message for the application. The message
  131. //      text is retrieved from the string resource table using LoadString.
  132. //
  133. //      Note that this function takes any valid argument list that can
  134. //      be passed to wsprintf. Because of this, the application must
  135. //      remember to cast near string pointers to FAR when built for Win 16.
  136. //      You will get a nice GP fault if you do not cast them correctly.
  137. //
  138. //  Arguments:
  139. //      HWND hwnd: Handle to parent window for message box holding the
  140. //      message.
  141. //
  142. //      UINT fuStyle: Style flags for MessageBox().
  143. //
  144. //      UINT uIdsFormat: String resource id to be loaded with LoadString()
  145. //      and used a the format string for wvsprintf().
  146. //
  147. //  Return (int):
  148. //      The return value is the result of MessageBox() if the string
  149. //      resource specified by uIdsFormat is valid. The return value is zero
  150. //      if the string resource failed to load.
  151. //
  152. //--------------------------------------------------------------------------;
  153.  
  154. int FNCGLOBAL AppMsgBoxId
  155. (
  156.     HWND                    hwnd,
  157.     UINT                    fuStyle,
  158.     UINT                    uIdsFormat,
  159.     ...
  160. )
  161. {
  162.     va_list     va;
  163.     TCHAR       szFormat[APP_MAX_STRING_RC_CHARS];
  164.     TCHAR       ach[APP_MAX_STRING_ERROR_CHARS];
  165.     int         n;
  166.  
  167.     n = LoadString(ghinst, uIdsFormat, szFormat, SIZEOF(szFormat));
  168.     if (0 != n)
  169.     {
  170.         //
  171.         //  format and display the message..
  172.         //
  173.         va_start(va, uIdsFormat);
  174.         wvsprintf(ach, szFormat, (LPSTR)va);
  175.         va_end(va);
  176.  
  177.         n = MessageBox(hwnd, ach, gszAppName, fuStyle);
  178.     }
  179.  
  180.     return (n);
  181. } // AppMsgBoxId()
  182.  
  183.  
  184. //--------------------------------------------------------------------------;
  185. //
  186. //  void AppHourGlass
  187. //
  188. //  Description:
  189. //      This function changes the cursor to that of the hour glass or
  190. //      back to the previous cursor.
  191. //
  192. //      This function can be called recursively.
  193. //
  194. //  Arguments:
  195. //      BOOL fHourGlass: TRUE if we need the hour glass.  FALSE if we need
  196. //      the arrow back.
  197. //
  198. //  Return (void):
  199. //      On return, the cursor will be what was requested.
  200. //
  201. //--------------------------------------------------------------------------;
  202.  
  203. void FNGLOBAL AppHourGlass
  204. (
  205.     BOOL                    fHourGlass
  206. )
  207. {
  208.     static HCURSOR  hcur;
  209.     static UINT     uWaiting = 0;
  210.  
  211.     if (fHourGlass)
  212.     {
  213.         if (!uWaiting)
  214.         {
  215.             hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  216.             ShowCursor(TRUE);
  217.         }
  218.  
  219.         uWaiting++;
  220.     }
  221.     else
  222.     {
  223.         --uWaiting;
  224.  
  225.         if (!uWaiting)
  226.         {
  227.             ShowCursor(FALSE);
  228.             SetCursor(hcur);
  229.         }
  230.     }
  231. } // AppHourGlass()
  232.  
  233.  
  234. //--------------------------------------------------------------------------;
  235. //
  236. //  BOOL AppYield
  237. //
  238. //  Description:
  239. //      This function yields by dispatching all messages stacked up in the
  240. //      application queue.
  241. //
  242. //  Arguments:
  243. //      HWND hwnd: Handle to main window of application if not yielding
  244. //      for a dialog. Handle to dialog box if yielding for a dialog box.
  245. //
  246. //      BOOL fIsDialog: TRUE if being called to yield for a dialog box.
  247. //
  248. //  Return (BOOL):
  249. //      The return value is always TRUE.
  250. //
  251. //--------------------------------------------------------------------------;
  252.  
  253. BOOL FNGLOBAL AppYield
  254. (
  255.     HWND                    hwnd,
  256.     BOOL                    fIsDialog
  257. )
  258. {
  259.     MSG     msg;
  260.  
  261.     if (fIsDialog)
  262.     {
  263.         while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  264.         {
  265.             if ((NULL == hwnd) || !IsDialogMessage(hwnd, &msg))
  266.             {
  267.                 TranslateMessage(&msg);
  268.                 DispatchMessage(&msg);
  269.             }
  270.         }
  271.     }
  272.     else
  273.     {
  274.         while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  275.         {
  276.             TranslateMessage(&msg);
  277.             DispatchMessage(&msg);
  278.         }
  279.     }
  280.  
  281.     return (TRUE);
  282. } // AppYield()
  283.  
  284.  
  285. //--------------------------------------------------------------------------;
  286. //
  287. //  int AppSetWindowText
  288. //
  289. //  Description:
  290. //      This function formats a string and sets the specified window text
  291. //      to the result.
  292. //
  293. //  Arguments:
  294. //      HWND hwnd: Handle to window to receive the new text.
  295. //
  296. //      PTSTR pszFormat: Pointer to any valid format for wsprintf.
  297. //
  298. //  Return (int):
  299. //      The return value is the number of bytes that the resulting window
  300. //      text was.
  301. //
  302. //--------------------------------------------------------------------------;
  303.  
  304. int FNCGLOBAL AppSetWindowText
  305. (
  306.     HWND                    hwnd,
  307.     PTSTR                   pszFormat,
  308.     ...
  309. )
  310. {
  311.     va_list     va;
  312.     TCHAR       ach[APP_MAX_STRING_ERROR_CHARS];
  313.     int         n;
  314.  
  315.     //
  316.     //  format and display the string in the window...
  317.     //
  318.     va_start(va, pszFormat);
  319.     n = wvsprintf(ach, pszFormat, (LPSTR)va);
  320.     va_end(va);
  321.  
  322.     SetWindowText(hwnd, ach);
  323.  
  324.     return (n);
  325. } // AppSetWindowText()
  326.  
  327.  
  328. //--------------------------------------------------------------------------;
  329. //
  330. //  int AppSetWindowTextId
  331. //
  332. //  Description:
  333. //      This function formats a string and sets the specified window text
  334. //      to the result. The format string is extracted from the string
  335. //      table using LoadString() on the uIdsFormat argument.
  336. //
  337. //  Arguments:
  338. //      HWND hwnd: Handle to window to receive the new text.
  339. //
  340. //      UINT uIdsFormat: String resource id to be loaded with LoadString()
  341. //      and used a the format string for wvsprintf().
  342. //
  343. //  Return (int):
  344. //      The return value is the number of bytes that the resulting window
  345. //      text was. This value is zero if the LoadString() function fails
  346. //      for the uIdsFormat argument.
  347. //
  348. //--------------------------------------------------------------------------;
  349.  
  350. int FNCGLOBAL AppSetWindowTextId
  351. (
  352.     HWND                    hwnd,
  353.     UINT                    uIdsFormat,
  354.     ...
  355. )
  356. {
  357.     va_list     va;
  358.     TCHAR       szFormat[APP_MAX_STRING_RC_CHARS];
  359.     TCHAR       ach[APP_MAX_STRING_ERROR_CHARS];
  360.     int         n;
  361.  
  362.     n = LoadString(ghinst, uIdsFormat, szFormat, SIZEOF(szFormat));
  363.     if (0 != n)
  364.     {
  365.         //
  366.         //  format and display the string in the window...
  367.         //
  368.         va_start(va, uIdsFormat);
  369.         n = wvsprintf(ach, szFormat, (LPSTR)va);
  370.         va_end(va);
  371.  
  372.         SetWindowText(hwnd, ach);
  373.     }
  374.  
  375.     return (n);
  376. } // AppSetWindowTextId()
  377.  
  378.  
  379. //--------------------------------------------------------------------------;
  380. //  
  381. //  BOOL AppFormatBigNumber
  382. //  
  383. //  Description:
  384. //  
  385. //  
  386. //  Arguments:
  387. //      LPTSTR pszNumber:
  388. //  
  389. //      DWORD dw:
  390. //  
  391. //  Return (BOOL):
  392. //  
  393. //--------------------------------------------------------------------------;
  394.  
  395. BOOL FNGLOBAL AppFormatBigNumber
  396. (
  397.     LPTSTR                  pszNumber,
  398.     DWORD                   dw
  399. )
  400. {
  401.     //
  402.     //  this is ugly...
  403.     //
  404.     //
  405.     if (dw >= 1000000000L)
  406.     {
  407.         wsprintf(pszNumber, TEXT("%u,%03u,%03u,%03u"),
  408.                             (WORD)(dw / 1000000000L),
  409.                             (WORD)((dw % 1000000000L) / 1000000L),
  410.                             (WORD)((dw % 1000000L) / 1000),
  411.                             (WORD)(dw % 1000));
  412.     }
  413.     else if (dw >= 1000000L)
  414.     {
  415.         wsprintf(pszNumber, TEXT("%u,%03u,%03u"),
  416.                             (WORD)(dw / 1000000L),
  417.                             (WORD)((dw % 1000000L) / 1000),
  418.                             (WORD)(dw % 1000));
  419.     }
  420.     else if (dw >= 1000)
  421.     {
  422.         wsprintf(pszNumber, TEXT("%u,%03u"),
  423.                             (WORD)(dw / 1000),
  424.                             (WORD)(dw % 1000));
  425.     }
  426.     else
  427.     {
  428.         wsprintf(pszNumber, TEXT("%lu"), dw);
  429.     }
  430.  
  431.  
  432.     return (TRUE);
  433. } // AppFormatBigNumber()
  434.  
  435.  
  436. //--------------------------------------------------------------------------;
  437. //  
  438. //  BOOL AppFormatDosDateTime
  439. //  
  440. //  Description:
  441. //  
  442. //  
  443. //  Arguments:
  444. //      LPTSTR pszDateTime:
  445. //  
  446. //      UINT uDosDate:
  447. //  
  448. //      UINT uDosTime:
  449. //  
  450. //  Return (BOOL):
  451. //  
  452. //--------------------------------------------------------------------------;
  453.  
  454. BOOL FNGLOBAL AppFormatDosDateTime
  455. (
  456.     LPTSTR                  pszDateTime,
  457.     UINT                    uDosDate,
  458.     UINT                    uDosTime
  459. )
  460. {
  461.     static TCHAR        szFormatDateTime[]  = TEXT("%.02u/%.02u/%.02u  %.02u:%.02u:%.02u");
  462.  
  463.     UINT                uDateMonth;
  464.     UINT                uDateDay;
  465.     UINT                uDateYear;
  466.     UINT                uTimeHour;
  467.     UINT                uTimeMinute;
  468.     UINT                uTimeSecond;
  469.  
  470.     //
  471.     //
  472.     //
  473.     uTimeHour   = uDosTime >> 11;
  474.     uTimeMinute = (uDosTime & 0x07E0) >> 5;
  475.     uTimeSecond = (uDosTime & 0x001F) << 1;
  476.  
  477.     uDateMonth  = (uDosDate & 0x01E0) >> 5;
  478.     uDateDay    = (uDosDate & 0x001F);
  479.     uDateYear   = (uDosDate >> 9) + 80;
  480.  
  481.     //
  482.     //
  483.     //
  484.     //
  485.     wsprintf(pszDateTime, szFormatDateTime,
  486.              uDateMonth,
  487.              uDateDay,
  488.              uDateYear,
  489.              uTimeHour,
  490.              uTimeMinute,
  491.              uTimeSecond);
  492.  
  493.     return (TRUE);
  494. } // AppFormatDosDateTime()
  495.  
  496.  
  497. //--------------------------------------------------------------------------;
  498. //
  499. //  void AcmAppDebugLog
  500. //
  501. //  Description:
  502. //      This function logs information to the debugger if the Debug Log
  503. //      option is set. You can then run DBWin (or something similar)
  504. //      to redirect the output whereever you want. Very useful for debugging
  505. //      ACM drivers.
  506. //
  507. //  Arguments:
  508. //      PTSTR pszFormat: Pointer to any valid format for wsprintf.
  509. //
  510. //  Return (void):
  511. //      None.
  512. //
  513. //--------------------------------------------------------------------------;
  514.  
  515. void FNCGLOBAL AcmAppDebugLog
  516. (
  517.     PTSTR                   pszFormat,
  518.     ...
  519. )
  520. {
  521.     static  TCHAR   szDebugLogSeparator[] = TEXT("=============================================================================\r\n");
  522.  
  523.     va_list     va;
  524.     TCHAR       ach[APP_MAX_STRING_ERROR_CHARS];
  525.  
  526.  
  527.     //
  528.     //  !!! UNICODE !!!
  529.     //
  530.     //
  531.     if (0 != (APP_OPTIONSF_DEBUGLOG & gfuAppOptions))
  532.     {
  533.         if (NULL == pszFormat)
  534.         {
  535.             OutputDebugString(szDebugLogSeparator);
  536.             return;
  537.         }
  538.  
  539.         //
  540.         //  format and display the string in a message box...
  541.         //
  542.         va_start(va, pszFormat);
  543.         wvsprintf(ach, pszFormat, (LPSTR)va);
  544.         va_end(va);
  545.  
  546.         OutputDebugString(ach);
  547.     }
  548. } // AcmAppDebugLog()
  549.  
  550.  
  551. //--------------------------------------------------------------------------;
  552. //  
  553. //  int MEditPrintF
  554. //  
  555. //  Description:
  556. //      This function is used to print formatted text into a Multiline
  557. //      Edit Control as if it were a standard console display. This is
  558. //      a very easy way to display small amounts of text information
  559. //      that can be scrolled and copied to the clip-board.
  560. //  
  561. //  Arguments:
  562. //      HWND hedit: Handle to a Multiline Edit control.
  563. //  
  564. //      PTSTR pszFormat: Pointer to any valid format for wsprintf. If
  565. //      this argument is NULL, then the Multiline Edit Control is cleared
  566. //      of all text.
  567. //
  568. //
  569. //  Return (int):
  570. //      Returns the number of characters written into the edit control.
  571. //
  572. //  Notes:
  573. //      The pszFormat string can contain combinations of escapes that 
  574. //      modify the default behaviour of this function. Escapes are single
  575. //      character codes placed at the _beginning_ of the format string.
  576. //
  577. //      Current escapes defined are:
  578. //
  579. //      ~   :   Suppresses the default CR/LF added to the end of the 
  580. //              printed line. Since the most common use of this function
  581. //              is to output a whole line of text with a CR/LF, that is
  582. //              the default.
  583. //
  584. //      `   :   Suppresses logging to the debug terminal (regardless of
  585. //              the global debug log options flag).
  586. //
  587. //  
  588. //--------------------------------------------------------------------------;
  589.  
  590. int FNCGLOBAL MEditPrintF
  591. (
  592.     HWND                    hedit,
  593.     PTSTR                   pszFormat,
  594.     ...
  595. )
  596. {
  597.     static  TCHAR   szCRLF[]              = TEXT("\r\n");
  598.  
  599.     va_list     va;
  600.     TCHAR       ach[APP_MAX_STRING_RC_CHARS];
  601.     int         n;
  602.     BOOL        fCRLF;
  603.     BOOL        fDebugLog;
  604.  
  605.     //
  606.     //  default the escapes
  607.     //
  608.     fCRLF     = TRUE;
  609.     fDebugLog = TRUE;
  610.  
  611.  
  612.     //
  613.     //  if the pszFormat argument is NULL, then just clear all text in
  614.     //  the edit control..
  615.     //
  616.     if (NULL == pszFormat)
  617.     {
  618.         SetWindowText(hedit, gszNull);
  619.  
  620.         AcmAppDebugLog(NULL);
  621.  
  622.         return (0);
  623.     }
  624.  
  625.     //
  626.     //  format and display the string in the window... first search for
  627.     //  escapes to modify default behaviour.
  628.     //
  629.     for (;;)
  630.     {
  631.         switch (*pszFormat)
  632.         {
  633.             case '~':
  634.                 fCRLF = FALSE;
  635.                 pszFormat++;
  636.                 continue;
  637.  
  638.             case '`':
  639.                 fDebugLog = FALSE;
  640.                 pszFormat++;
  641.                 continue;
  642.         }
  643.  
  644.         break;
  645.     }
  646.  
  647.     va_start(va, pszFormat);
  648.     n = wvsprintf(ach, pszFormat, (LPSTR)va);
  649.     va_end(va);
  650.  
  651.     Edit_SetSel(hedit, (WPARAM)-1, (LPARAM)-1);
  652.     Edit_ReplaceSel(hedit, ach);
  653.  
  654.     if (fDebugLog)
  655.     {
  656.         AcmAppDebugLog(ach);
  657.     }
  658.  
  659.     if (fCRLF)
  660.     {
  661.         Edit_SetSel(hedit, (WPARAM)-1, (LPARAM)-1);
  662.         Edit_ReplaceSel(hedit, szCRLF);
  663.  
  664.         if (fDebugLog)
  665.         {
  666.             AcmAppDebugLog(szCRLF);
  667.         }
  668.     }
  669.  
  670.     return (n);
  671. } // MEditPrintF()
  672.  
  673.  
  674. //--------------------------------------------------------------------------;
  675. //
  676. //  BOOL AppGetFileTitle
  677. //
  678. //  Description:
  679. //      This function extracts the file title from a file path and returns
  680. //      it in the caller's specified buffer.
  681. //
  682. //  Arguments:
  683. //      PTSTR pszFilePath: Pointer to null terminated file path.
  684. //
  685. //      PTSTR pszFileTitle: Pointer to buffer to receive the file title.
  686. //
  687. //  Return (BOOL):
  688. //      Always returns TRUE. But should return FALSE if this function
  689. //      checked for bogus values, etc.
  690. //
  691. //
  692. //--------------------------------------------------------------------------;
  693.  
  694. BOOL FNGLOBAL AppGetFileTitle
  695. (
  696.     PTSTR                   pszFilePath,
  697.     PTSTR                   pszFileTitle
  698. )
  699. {
  700.     #define IS_SLASH(c)     ('/' == (c) || '\\' == (c))
  701.  
  702.     PTSTR       pch;
  703.  
  704.     //
  705.     //  scan to the end of the file path string..
  706.     //
  707.     for (pch = pszFilePath; '\0' != *pch; pch++)
  708.         ;
  709.  
  710.     //
  711.     //  now scan back toward the beginning of the string until a slash (\),
  712.     //  colon, or start of the string is encountered.
  713.     //
  714.     while ((pch >= pszFilePath) && !IS_SLASH(*pch) && (':' != *pch))
  715.     {
  716.         pch--;
  717.     }
  718.  
  719.     //
  720.     //  finally, copy the 'title' into the destination buffer.. skip ahead
  721.     //  one char since the above loop steps back one too many chars...
  722.     //
  723.     lstrcpy(pszFileTitle, ++pch);
  724.  
  725.     return (TRUE);
  726. } // AppGetFileTitle()
  727.  
  728.  
  729. //--------------------------------------------------------------------------;
  730. //
  731. //  BOOL AppGetFileName
  732. //
  733. //  Description:
  734. //      This function is a wrapper for the Get[Open/Save]FileName commdlg
  735. //      chooser dialogs. Based on the fuFlags argument, this function will
  736. //      display the appropriate chooser dialog and return the result.
  737. //
  738. //  Arguments:
  739. //      HWND hwnd: Handle to parent window for chooser dialog.
  740. //
  741. //      PTSTR pszFilePath: Pointer to buffer to receive the file path.
  742. //
  743. //      PTSTR pszFileTitle: Pointer to buffer to receive the file title.
  744. //      This argument may be NULL, in which case no title will be returned.
  745. //
  746. //      UINT fuFlags:
  747. //
  748. //  Return (BOOL):
  749. //      The return value is TRUE if a file was chosen. It is FALSE if the
  750. //      user canceled the operation.
  751. //
  752. //
  753. //--------------------------------------------------------------------------;
  754.  
  755. BOOL FNGLOBAL AppGetFileName
  756. (
  757.     HWND                    hwnd,
  758.     PTSTR                   pszFilePath,
  759.     PTSTR                   pszFileTitle,
  760.     UINT                    fuFlags
  761. )
  762. {
  763.     #define APP_OFN_FLAGS_SAVE  (OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT)
  764.     #define APP_OFN_FLAGS_OPEN  (OFN_HIDEREADONLY | OFN_FILEMUSTEXIST)
  765.  
  766.     TCHAR               szExtDefault[APP_MAX_EXT_DEFAULT_CHARS];
  767.     TCHAR               szExtFilter[APP_MAX_EXT_FILTER_CHARS];
  768.     OPENFILENAME        ofn;
  769.     BOOL                f;
  770.     PTCHAR              pch;
  771.  
  772.  
  773.     //
  774.     //  get the extension filter and default extension for this application
  775.     //
  776.     LoadString(ghinst, IDS_OFN_EXT_DEF, szExtDefault, SIZEOF(szExtDefault));
  777.     LoadString(ghinst, IDS_OFN_EXT_FILTER, szExtFilter, SIZEOF(szExtFilter));
  778.  
  779.  
  780.     //
  781.     //  NOTE! building the filter string for the OPENFILENAME structure
  782.     //  is a bit more difficult when dealing with Unicode and C8's new
  783.     //  optimizer. it joyfully removes literal '\0' characters from
  784.     //  strings that are concatted together. if you try making each
  785.     //  string separate (array of pointers to strings), the compiler
  786.     //  will dword align them... etc, etc.
  787.     //
  788.     //  if you can think of a better way to build the silly filter string
  789.     //  for common dialogs and still work in Win 16 and Win 32 [Unicode]
  790.     //  i'd sure like to hear about it...
  791.     //
  792.     for (pch = &szExtFilter[0]; '\0' != *pch; pch++)
  793.     {
  794.         if ('!' == *pch)
  795.             *pch = '\0';
  796.     }
  797.  
  798.     //
  799.     //  initialize the OPENFILENAME members
  800.     //
  801.     memset(&ofn, 0, sizeof(OPENFILENAME));
  802.  
  803.     pszFilePath[0]          = '\0';
  804.     if (pszFileTitle)
  805.         pszFileTitle[0]     = '\0';
  806.  
  807.     ofn.lStructSize         = sizeof(OPENFILENAME);
  808.     ofn.hwndOwner           = hwnd;
  809.     ofn.lpstrFilter         = szExtFilter;
  810.     ofn.lpstrCustomFilter   = NULL;
  811.     ofn.nMaxCustFilter      = 0L;
  812.     ofn.nFilterIndex        = 1L;
  813.     ofn.lpstrFile           = pszFilePath;
  814.     ofn.nMaxFile            = APP_MAX_FILE_PATH_CHARS;
  815.     ofn.lpstrFileTitle      = pszFileTitle;
  816.     ofn.nMaxFileTitle       = pszFileTitle ? APP_MAX_FILE_TITLE_CHARS : 0;
  817.     if (fuFlags & APP_GETFILENAMEF_SAVE)
  818.     {
  819.         ofn.lpstrInitialDir = gszInitialDirSave;
  820.     }
  821.     else
  822.     {
  823.         ofn.lpstrInitialDir = gszInitialDirOpen;
  824.     }
  825.     ofn.nFileOffset         = 0;
  826.     ofn.nFileExtension      = 0;
  827.     ofn.lpstrDefExt         = szExtDefault;
  828.  
  829.     //
  830.     //  if the fuFlags.APP_GETFILENAMEF_SAVE bit is set, then call
  831.     //  GetSaveFileName() otherwise call GetOpenFileName(). why commdlg was
  832.     //  designed with two separate functions for save and open only clark
  833.     //  knows.
  834.     //
  835.     if (fuFlags & APP_GETFILENAMEF_SAVE)
  836.     {
  837.         ofn.Flags = APP_OFN_FLAGS_SAVE;
  838.         f = GetSaveFileName(&ofn);
  839.         if (f)
  840.         {
  841.             if (NULL != pszFilePath)
  842.             {
  843.                 lstrcpy(gszInitialDirSave, pszFilePath);
  844.  
  845.                 pch = &gszInitialDirSave[lstrlen(gszInitialDirSave) - 1];
  846.                 for ( ; gszInitialDirSave != pch; pch--)
  847.                 {
  848.                     if ('\\' == *pch)
  849.                     {
  850.                         *pch = '\0';
  851.                         break;
  852.                     }
  853.                 }
  854.             }
  855.         }
  856.     }
  857.     else
  858.     {
  859.         ofn.Flags = APP_OFN_FLAGS_OPEN;
  860.         f = GetOpenFileName(&ofn);
  861.         if (f)
  862.         {
  863.             if (NULL != pszFilePath)
  864.             {
  865.                 lstrcpy(gszInitialDirOpen, pszFilePath);
  866.  
  867.                 pch = &gszInitialDirOpen[lstrlen(gszInitialDirOpen) - 1];
  868.                 for ( ; gszInitialDirOpen != pch; pch--)
  869.                 {
  870.                     if ('\\' == *pch)
  871.                     {
  872.                         *pch = '\0';
  873.                         break;
  874.                     }
  875.                 }
  876.             }
  877.         }
  878.     }
  879.  
  880.     return (f);
  881. } // AppGetFileName()
  882.  
  883.  
  884. //--------------------------------------------------------------------------;
  885. //
  886. //  BOOL AppTitle
  887. //
  888. //  Description:
  889. //      This function formats and sets the title text of the application's
  890. //      window.
  891. //
  892. //  Arguments:
  893. //      HWND hwnd: Handle to application window to set title text for.
  894. //
  895. //      PTSTR pszFileTitle: Pointer to file title to display.
  896. //
  897. //  Return (BOOL):
  898. //      The return value is always TRUE.
  899. //
  900. //
  901. //--------------------------------------------------------------------------;
  902.  
  903. BOOL FNGLOBAL AppTitle
  904. (
  905.     HWND                    hwnd,
  906.     PTSTR                   pszFileTitle
  907. )
  908. {
  909.     static  TCHAR   szFormatTitle[]     = TEXT("%s - %s");
  910.  
  911.     TCHAR       ach[APP_MAX_FILE_PATH_CHARS];
  912.  
  913.     //
  914.     //  format the title text as 'AppName - FileTitle'
  915.     //
  916.     wsprintf(ach, szFormatTitle, (LPSTR)gszAppName, (LPSTR)pszFileTitle);
  917.     SetWindowText(hwnd, ach);
  918.  
  919.     return (TRUE);
  920. } // AppTitle()
  921.  
  922.  
  923. //--------------------------------------------------------------------------;
  924. //
  925. //  BOOL AppFileNew
  926. //
  927. //  Description:
  928. //      This function is called to handle the IDM_FILE_NEW message. It is
  929. //      responsible for clearing the working area for a new unnamed file.
  930. //
  931. //  Arguments:
  932. //      HWND hwnd: Handle to application window.
  933. //
  934. //      PACMAPPFILEDESC paafd: Pointer to current file descriptor.
  935. //
  936. //  Return (BOOL):
  937. //      The return value is TRUE if the working area was cleared and is
  938. //      ready for new stuff. The return value is FALSE if the user canceled
  939. //      the operation.
  940. //
  941. //--------------------------------------------------------------------------;
  942.  
  943. BOOL FNGLOBAL AppFileNew
  944. (
  945.     HWND                    hwnd,
  946.     PACMAPPFILEDESC         paafd,
  947.     BOOL                    fCreate
  948. )
  949. {
  950.     BOOL                f;
  951.  
  952.     if (fCreate)
  953.     {
  954.         f = AcmAppFileNew(hwnd, paafd);
  955.         if (!f)
  956.             return (FALSE);
  957.     }
  958.     else
  959.     {
  960.         //
  961.         //  if there is currently a file path, then we have to do some real
  962.         //  work...
  963.         //
  964.         if ('\0' != paafd->szFilePath[0])
  965.         {
  966.             f = AcmAppFileNew(hwnd, paafd);
  967.             if (!f)
  968.                 return (FALSE);
  969.         }
  970.  
  971.         //
  972.         //  blow away the old file path and title; set the window title
  973.         //  and return success
  974.         //
  975.         lstrcpy(paafd->szFilePath, gszFileUntitled);
  976.         lstrcpy(paafd->szFileTitle, gszFileUntitled);
  977.     }
  978.  
  979.     AppTitle(hwnd, paafd->szFileTitle);
  980.  
  981.     AcmAppDisplayFileProperties(hwnd, paafd);
  982.  
  983.     return (TRUE);
  984. } // AppFileNew()
  985.  
  986.  
  987. //--------------------------------------------------------------------------;
  988. //
  989. //  BOOL AppFileOpen
  990. //
  991. //  Description:
  992. //      This function handles the IDM_FILE_OPEN message. It is responsible
  993. //      for getting a new file name from the user and opening that file
  994. //      if possible.
  995. //
  996. //  Arguments:
  997. //      HWND hwnd: Handle to application window.
  998. //
  999. //      PACMAPPFILEDESC paafd: Pointer to current file descriptor.
  1000. //
  1001. //  Return (BOOL):
  1002. //      The return value is TRUE if a new file was selected and opened.
  1003. //      It is FALSE if the user canceled the operation.
  1004. //
  1005. //--------------------------------------------------------------------------;
  1006.  
  1007. BOOL FNLOCAL AppFileOpen
  1008. (
  1009.     HWND                    hwnd,
  1010.     PACMAPPFILEDESC         paafd
  1011. )
  1012. {
  1013.     TCHAR               szFilePath[APP_MAX_FILE_PATH_CHARS];
  1014.     TCHAR               szFileTitle[APP_MAX_FILE_TITLE_CHARS];
  1015.     BOOL                f;
  1016.  
  1017.     //
  1018.     //  first test for a modified file that has not been saved. if the
  1019.     //  return value is FALSE we should cancel the File.Open operation.
  1020.     //
  1021.     f = AcmAppFileSaveModified(hwnd, paafd);
  1022.     if (!f)
  1023.         return (FALSE);
  1024.  
  1025.  
  1026.     //
  1027.     //  get the file name of the new file into temporary buffers (so
  1028.     //  if we fail to open it we can back out cleanly).
  1029.     //
  1030.     f = AppGetFileName(hwnd, szFilePath, szFileTitle, APP_GETFILENAMEF_OPEN);
  1031.     if (!f)
  1032.         return (FALSE);
  1033.  
  1034.  
  1035.     //!!!
  1036.     //  read the new file...
  1037.     //
  1038.     lstrcpy(paafd->szFilePath, szFilePath);
  1039.     lstrcpy(paafd->szFileTitle, szFileTitle);
  1040.  
  1041.     f = AcmAppFileOpen(hwnd, paafd);
  1042.     if (f)
  1043.     {
  1044.         //
  1045.         //  set the window title text...
  1046.         //
  1047.         AppTitle(hwnd, szFileTitle);
  1048.         AcmAppDisplayFileProperties(hwnd, paafd);
  1049.     }
  1050.  
  1051.     return (f);
  1052. } // AppFileOpen()
  1053.  
  1054.  
  1055. //--------------------------------------------------------------------------;
  1056. //
  1057. //  BOOL AppFileSave
  1058. //
  1059. //  Description:
  1060. //      This function handles the IDM_FILE_SAVE[AS] messages. It is
  1061. //      responsible for saving the current file. If a file name needs
  1062. //      to be specified then the save file dialog is displayed.
  1063. //
  1064. //  Arguments:
  1065. //      HWND hwnd: Handle to application window.
  1066. //
  1067. //      PACMAPPFILEDESC paafd: Pointer to current file descriptor.
  1068. //
  1069. //      BOOL fSaveAs: TRUE if the save file chooser should be displayed
  1070. //      before saving the file. FALSE if should operate like File.Save.
  1071. //
  1072. //  Return (BOOL):
  1073. //      The return value is TRUE if the file was saved. It is FALSE if the
  1074. //      user canceled the operation or the file does not need saved.
  1075. //
  1076. //--------------------------------------------------------------------------;
  1077.  
  1078. BOOL FNGLOBAL AppFileSave
  1079. (
  1080.     HWND                    hwnd,
  1081.     PACMAPPFILEDESC         paafd,
  1082.     BOOL                    fSaveAs
  1083. )
  1084. {
  1085.     TCHAR               szFilePath[APP_MAX_FILE_PATH_CHARS];
  1086.     TCHAR               szFileTitle[APP_MAX_FILE_TITLE_CHARS];
  1087.     BOOL                f;
  1088.  
  1089.     //
  1090.     //
  1091.     //
  1092.     lstrcpy(szFilePath, paafd->szFilePath);
  1093.     lstrcpy(szFileTitle, paafd->szFileTitle);
  1094.  
  1095.  
  1096.     //
  1097.     //  check if we should bring up the save file chooser dialog...
  1098.     //
  1099.     if (fSaveAs || (0 == lstrcmp(paafd->szFileTitle, gszFileUntitled)))
  1100.     {
  1101.         //
  1102.         //  get the file name for saving the data to into temporary
  1103.         //  buffers (so if we fail to save it we can back out cleanly).
  1104.         //
  1105.         f = AppGetFileName(hwnd, szFilePath, szFileTitle, APP_GETFILENAMEF_SAVE);
  1106.         if (!f)
  1107.             return (FALSE);
  1108.     }
  1109.  
  1110.     //
  1111.     //  save the file...
  1112.     //
  1113.     f = AcmAppFileSave(hwnd, paafd, szFilePath, szFileTitle, 0);
  1114.     if (f)
  1115.     {
  1116.         //
  1117.         //  changes have been saved, so clear the modified bit...
  1118.         //
  1119.         paafd->fdwState &= ~ACMAPPFILEDESC_STATEF_MODIFIED;
  1120.  
  1121.         AppTitle(hwnd, paafd->szFileTitle);
  1122.  
  1123.         AcmAppDisplayFileProperties(hwnd, paafd);
  1124.     }
  1125.  
  1126.     return (f);
  1127. } // AppFileSave()
  1128.  
  1129.  
  1130. //==========================================================================;
  1131. //
  1132. //  Main application window handling code...
  1133. //
  1134. //
  1135. //==========================================================================;
  1136.  
  1137. //--------------------------------------------------------------------------;
  1138. //
  1139. //  LRESULT AppInitMenuPopup
  1140. //
  1141. //  Description:
  1142. //      This function handles the WM_INITMENUPOPUP message. This message
  1143. //      is sent to the window owning the menu that is going to become
  1144. //      active. This gives an application the ability to modify the menu
  1145. //      before it is displayed (disable/add items, etc).
  1146. //
  1147. //  Arguments:
  1148. //      HWND hwnd: Handle to window that generated the WM_INITMENUPOPUP
  1149. //      message.
  1150. //
  1151. //      HMENU hmenu: Handle to the menu that is to become active.
  1152. //
  1153. //      int nItem: Specifies the zero-based relative position of the menu
  1154. //      item that invoked the popup menu.
  1155. //
  1156. //      BOOL fSysMenu: Specifies whether the popup menu is a System menu
  1157. //      (TRUE) or it is not a System menu (FALSE).
  1158. //
  1159. //  Return (LRESULT):
  1160. //      Returns zero if the message is processed.
  1161. //
  1162. //--------------------------------------------------------------------------;
  1163.  
  1164. LRESULT FNLOCAL AppInitMenuPopup
  1165. (
  1166.     HWND                    hwnd,
  1167.     HMENU                   hmenu,
  1168.     int                     nItem,
  1169.     BOOL                    fSysMenu
  1170. )
  1171. {
  1172.     BOOL                f;
  1173.     int                 nSelStart;
  1174.     int                 nSelEnd;
  1175.     HWND                hedit;
  1176.  
  1177.     DPF(4, "AppInitMenuPopup(hwnd=%Xh, hmenu=%Xh, nItem=%d, fSysMenu=%d)",
  1178.             hwnd, hmenu, nItem, fSysMenu);
  1179.  
  1180.     //
  1181.     //  if the system menu is what got hit, succeed immediately... this
  1182.     //  application has no stuff in the system menu.
  1183.     //
  1184.     if (fSysMenu)
  1185.         return (0L);
  1186.  
  1187.     //
  1188.     //  initialize the menu that is being 'popped up'
  1189.     //
  1190.     switch (nItem)
  1191.     {
  1192.         case APP_MENU_ITEM_FILE:
  1193.             EnableMenuItem(hmenu, IDM_FILE_NEW,
  1194.                            (UINT)(gfAcmAvailable ? MF_ENABLED : MF_GRAYED));
  1195.  
  1196.             f = (NULL != gaafd.pwfx);
  1197.             EnableMenuItem(hmenu, IDM_FILE_SNDPLAYSOUND_PLAY,
  1198.                            (UINT)(f ? MF_ENABLED : MF_GRAYED));
  1199.             EnableMenuItem(hmenu, IDM_FILE_SNDPLAYSOUND_STOP,
  1200.                            (UINT)(f ? MF_ENABLED : MF_GRAYED));
  1201.  
  1202.             f = (NULL != gaafd.pwfx) && gfAcmAvailable;
  1203.             EnableMenuItem(hmenu, IDM_FILE_CONVERT,
  1204.                            (UINT)(f ? MF_ENABLED : MF_GRAYED));
  1205.  
  1206.  
  1207.             //
  1208.             //  if the file has been modified, then enable the File.Save
  1209.             //  menu
  1210.             //
  1211.             f = (0 != (gaafd.fdwState & ACMAPPFILEDESC_STATEF_MODIFIED));
  1212.             EnableMenuItem(hmenu, IDM_FILE_SAVE,
  1213.                            (UINT)(f ? MF_ENABLED : MF_GRAYED));
  1214.  
  1215.             // f = (NULL != gaafd.pwfx);
  1216.             EnableMenuItem(hmenu, IDM_FILE_SAVEAS,
  1217.                            (UINT)(f ? MF_ENABLED : MF_GRAYED));
  1218.             break;
  1219.  
  1220.         case APP_MENU_ITEM_EDIT:
  1221.             //
  1222.             //  check to see if something is selected in the display
  1223.             //  window and enable/disable Edit menu options appropriately
  1224.             //
  1225.             hedit = GetDlgItem(hwnd, IDD_ACMAPP_EDIT_DISPLAY);
  1226.             Edit_GetSelEx(hedit, &nSelStart, &nSelEnd);
  1227.  
  1228.             f = (nSelStart != nSelEnd);
  1229.             EnableMenuItem(hmenu, WM_COPY,  (UINT)(f ? MF_ENABLED : MF_GRAYED));
  1230.             break;
  1231.  
  1232.         case APP_MENU_ITEM_VIEW:
  1233.             EnableMenuItem(hmenu, IDM_VIEW_ACM_DRIVERS,
  1234.                            (UINT)(gfAcmAvailable ? MF_ENABLED : MF_GRAYED));
  1235.             break;
  1236.  
  1237.  
  1238.         case APP_MENU_ITEM_OPTIONS:
  1239.             f = (0 != waveInGetNumDevs());
  1240.             EnableMenuItem(hmenu, IDM_OPTIONS_WAVEINDEVICE,  (UINT)(f ? MF_ENABLED : MF_GRAYED));
  1241.  
  1242.             f = (0 != waveOutGetNumDevs());
  1243.             EnableMenuItem(hmenu, IDM_OPTIONS_WAVEOUTDEVICE, (UINT)(f ? MF_ENABLED : MF_GRAYED));
  1244.  
  1245.             //
  1246.             //  make sure the options that need a checkmark are checked..
  1247.             //
  1248.             f = (0 != (APP_OPTIONSF_AUTOOPEN & gfuAppOptions));
  1249.             CheckMenuItem(hmenu, IDM_OPTIONS_AUTOOPEN,
  1250.                           (UINT)(f ? MF_CHECKED : MF_UNCHECKED));
  1251.  
  1252.             f = (0 != (APP_OPTIONSF_DEBUGLOG & gfuAppOptions));
  1253.             CheckMenuItem(hmenu, IDM_OPTIONS_DEBUGLOG,
  1254.                           (UINT)(f ? MF_CHECKED : MF_UNCHECKED));
  1255.             break;
  1256.     }
  1257.  
  1258.     //
  1259.     //  we processed the message--return 0...
  1260.     //
  1261.     return (0L);
  1262. } // AppInitMenuPopup()
  1263.  
  1264.  
  1265. //--------------------------------------------------------------------------;
  1266. //
  1267. //  LRESULT AppCommand
  1268. //
  1269. //  Description:
  1270. //      This function handles the WM_COMMAND message.
  1271. //
  1272. //  Arguments:
  1273. //      HWND hwnd: Handle to window receiving the WM_COMMAND message.
  1274. //
  1275. //      int nId: Control or menu item identifier.
  1276. //
  1277. //      HWND hwndCtl: Handle of control if the message is from a control.
  1278. //      This argument is NULL if the message was not generated by a control.
  1279. //
  1280. //      UINT uCode: Notification code. This argument is 1 if the message
  1281. //      was generated by an accelerator. If the message is from a menu,
  1282. //      this argument is 0.
  1283. //
  1284. //  Return (LRESULT):
  1285. //      Returns zero if the message is processed.
  1286. //
  1287. //--------------------------------------------------------------------------;
  1288.  
  1289. LRESULT FNLOCAL AppCommand
  1290. (
  1291.     HWND                    hwnd,
  1292.     int                     nId,
  1293.     HWND                    hwndCtl,
  1294.     UINT                    uCode
  1295. )
  1296. {
  1297.     BOOL                f;
  1298.     DWORD               dw;
  1299.     UINT                uDevId;
  1300.  
  1301.     switch (nId)
  1302.     {
  1303.         case IDM_FILE_NEW:
  1304.             AppFileNew(hwnd, &gaafd, TRUE);
  1305.             break;
  1306.  
  1307.         case IDM_FILE_OPEN:
  1308.             AppFileOpen(hwnd, &gaafd);
  1309.             break;
  1310.  
  1311.         case IDM_FILE_SAVE:
  1312.             AppFileSave(hwnd, &gaafd, FALSE);
  1313.             break;
  1314.  
  1315.         case IDM_FILE_SAVEAS:
  1316.             AppFileSave(hwnd, &gaafd, TRUE);
  1317.             break;
  1318.  
  1319.  
  1320.         case IDM_FILE_SNDPLAYSOUND_PLAY:
  1321.             if (NULL == gaafd.pwfx)
  1322.             {
  1323.                 MessageBeep((UINT)-1);
  1324.                 break;
  1325.             }
  1326.  
  1327.             AppHourGlass(TRUE);
  1328.             dw = timeGetTime();
  1329.             f  = sndPlaySound(gaafd.szFilePath, SND_ASYNC | SND_NODEFAULT);
  1330.             dw = timeGetTime() - dw;
  1331.             AppHourGlass(FALSE);
  1332.  
  1333.             if (0 != (APP_OPTIONSF_DEBUGLOG & gfuAppOptions))
  1334.             {
  1335.                 AcmAppDebugLog(NULL);
  1336.                 AcmAppDebugLog(TEXT("sndPlaySound(%s) took %lu milliseconds to %s.\r\n"),
  1337.                                 (LPTSTR)gaafd.szFilePath,
  1338.                                 dw,
  1339.                                 f ? (LPTSTR)TEXT("succeed") : (LPTSTR)TEXT("fail"));
  1340.             }
  1341.             
  1342.             if (!f)
  1343.             {
  1344.                 AppMsgBox(hwnd, MB_OK | MB_ICONEXCLAMATION,
  1345.                           TEXT("The file '%s' cannot be played by sndPlaySound."),
  1346.                           (LPSTR)gaafd.szFilePath);
  1347.             }
  1348.             break;
  1349.  
  1350.         case IDM_FILE_SNDPLAYSOUND_STOP:
  1351.             sndPlaySound(NULL, 0L);
  1352.             break;
  1353.  
  1354.         case IDM_FILE_CONVERT:
  1355.             AcmAppFileConvert(hwnd, &gaafd);
  1356.             break;
  1357.  
  1358.  
  1359.         case IDM_FILE_ABOUT:
  1360.             DialogBox(ghinst, DLG_ABOUT, hwnd, AboutDlgProc);
  1361.             break;
  1362.  
  1363.         case IDM_FILE_EXIT:
  1364.             FORWARD_WM_CLOSE(hwnd, SendMessage);
  1365.             break;
  1366.  
  1367.  
  1368.         case WM_COPY:
  1369.             //
  1370.             //  pass on edit messages received to the display window
  1371.             //
  1372.             SendMessage(GetDlgItem(hwnd, IDD_ACMAPP_EDIT_DISPLAY), nId, 0, 0L);
  1373.             break;
  1374.  
  1375.         case IDM_EDIT_SELECTALL:
  1376.             Edit_SetSel(GetDlgItem(hwnd, IDD_ACMAPP_EDIT_DISPLAY), 0, -1);
  1377.             break;
  1378.  
  1379.  
  1380.         case IDM_UPDATE:
  1381.             AcmAppFileOpen(hwnd, &gaafd);
  1382.  
  1383.             AcmAppDisplayFileProperties(hwnd, &gaafd);
  1384.             break;
  1385.  
  1386.         case IDM_VIEW_SYSTEMINFO:
  1387.             DialogBox(ghinst, DLG_AADETAILS, hwnd, AcmAppSystemInfoDlgProc);
  1388.             break;
  1389.  
  1390.         case IDM_VIEW_ACM_DRIVERS:
  1391.             DialogBox(ghinst, DLG_AADRIVERS, hwnd, AcmAppDriversDlgProc);
  1392.             break;
  1393.  
  1394.  
  1395.         case IDM_OPTIONS_WAVEINDEVICE:
  1396.             uDevId = DialogBoxParam(ghinst, DLG_AAWAVEDEVICE, hwnd,
  1397.                                     AcmAppWaveDeviceDlgProc,
  1398.                                     MAKELONG((WORD)guWaveInId, TRUE));
  1399.  
  1400.             if (uDevId != guWaveInId)
  1401.             {
  1402.                 guWaveInId = uDevId;
  1403.                 AcmAppDisplayFileProperties(hwnd, &gaafd);
  1404.             }
  1405.             break;
  1406.  
  1407.         case IDM_OPTIONS_WAVEOUTDEVICE:
  1408.             uDevId = DialogBoxParam(ghinst, DLG_AAWAVEDEVICE, hwnd,
  1409.                                     AcmAppWaveDeviceDlgProc,
  1410.                                     MAKELONG((WORD)guWaveOutId, FALSE));
  1411.  
  1412.             if (uDevId != guWaveOutId)
  1413.             {
  1414.                 guWaveOutId = uDevId;
  1415.                 AcmAppDisplayFileProperties(hwnd, &gaafd);
  1416.             }
  1417.             break;
  1418.  
  1419.  
  1420.         case IDM_OPTIONS_AUTOOPEN:
  1421.             gfuAppOptions ^= APP_OPTIONSF_AUTOOPEN;
  1422.             break;
  1423.  
  1424.         case IDM_OPTIONS_DEBUGLOG:
  1425.             gfuAppOptions ^= APP_OPTIONSF_DEBUGLOG;
  1426.             break;
  1427.  
  1428.         case IDM_OPTIONS_FONT:
  1429.             AcmAppChooseFont(hwnd);
  1430.             break;
  1431.  
  1432.  
  1433.         case IDM_PLAYRECORD:
  1434.             if (NULL == gaafd.pwfx)
  1435.             {
  1436.                 f = AppFileNew(hwnd, &gaafd, TRUE);
  1437.                 if (!f)
  1438.                     break;
  1439.  
  1440.                 if (NULL == gaafd.pwfx)
  1441.                     break;
  1442.             }
  1443.  
  1444.             f = DialogBoxParam(ghinst, DLG_AAPLAYRECORD, hwnd,
  1445.                                AcmAppPlayRecord, (LPARAM)(LPVOID)&gaafd);
  1446.             if (f)
  1447.             {
  1448.                 AcmAppFileOpen(hwnd, &gaafd);
  1449.  
  1450.                 AcmAppDisplayFileProperties(hwnd, &gaafd);
  1451.             }
  1452.             break;
  1453.     }
  1454.  
  1455.     return (0L);
  1456. } // AppCommand()
  1457.  
  1458.  
  1459. //--------------------------------------------------------------------------;
  1460. //
  1461. //  BOOL AcmAppDlgProcDragDropContinue
  1462. //
  1463. //  Description:
  1464. //
  1465. //  Arguments:
  1466. //      HWND hwnd: Handle to window.
  1467. //
  1468. //      UINT uMsg: Message being sent to the window.
  1469. //
  1470. //      WPARAM wParam: Specific argument to message.
  1471. //
  1472. //      LPARAM lParam: Specific argument to message.
  1473. //
  1474. //  Return (BOOL):
  1475. //      The return value is specific to the message that was received. For
  1476. //      the most part, it is FALSE if this dialog procedure does not handle
  1477. //      a message.
  1478. //
  1479. //--------------------------------------------------------------------------;
  1480.  
  1481. BOOL FNEXPORT AcmAppDlgProcDragDropContinue
  1482. (
  1483.     HWND                    hwnd,
  1484.     UINT                    uMsg,
  1485.     WPARAM                  wParam,
  1486.     LPARAM                  lParam
  1487. )
  1488. {
  1489.     UINT                uId;
  1490.  
  1491.     switch (uMsg)
  1492.     {
  1493.         case WM_INITDIALOG:
  1494.             AppSetWindowText(hwnd, TEXT("File %u of %u"), LOWORD(lParam), HIWORD(lParam));
  1495.             return (TRUE);
  1496.  
  1497.         case WM_COMMAND:
  1498.             uId = GET_WM_COMMAND_ID(wParam, lParam);
  1499.             if ((IDOK == uId) || (IDCANCEL == uId))
  1500.             {
  1501.                 EndDialog(hwnd, uId);
  1502.             }
  1503.             break;
  1504.     }
  1505.  
  1506.     return (FALSE);
  1507. } // AcmAppDlgProcDragDropContinue()
  1508.  
  1509.  
  1510. //--------------------------------------------------------------------------;
  1511. //
  1512. //  LRESULT AppDropFiles
  1513. //
  1514. //  Description:
  1515. //      This function handles the WM_DROPFILES message. This message is
  1516. //      sent when files are 'dropped' on the window from file manager
  1517. //      (or other drag/drop servers made by ISV's that figured out the
  1518. //      undocumented internal workings of the SHELL).
  1519. //
  1520. //      A window must be registered to receive these messages either by
  1521. //      called DragAcceptFiles() or using CreateWindowEx() with the
  1522. //      WS_EX_ACCEPTFILES style bit.
  1523. //
  1524. //  Arguments:
  1525. //      HWND hwnd: Handle to window receiving the message.
  1526. //
  1527. //      HDROP hdrop: Handle to drop structure.
  1528. //
  1529. //  Return (LRESULT):
  1530. //      Returns 0 if the message is processed.
  1531. //
  1532. //--------------------------------------------------------------------------;
  1533.  
  1534. LRESULT FNLOCAL AppDropFiles
  1535. (
  1536.     HWND                    hwnd,
  1537.     HDROP                   hdrop
  1538. )
  1539. {
  1540.     TCHAR               szFilePath[APP_MAX_FILE_PATH_CHARS];
  1541.     UINT                cFiles;
  1542.     UINT                u;
  1543.     BOOL                f;
  1544.     int                 n;
  1545.  
  1546.     //
  1547.     //  first test for a file that has not been saved. if the return
  1548.     //  value is FALSE we should cancel the drop operation.
  1549.     //
  1550.     f = AcmAppFileSaveModified(hwnd, &gaafd);
  1551.     if (!f)
  1552.     {
  1553.         goto App_Drop_Files_Exit;
  1554.     }
  1555.  
  1556.     //
  1557.     //  get number of files dropped on our window
  1558.     //
  1559.     cFiles = DragQueryFile(hdrop, (UINT)-1, NULL, 0);
  1560.  
  1561.     DPF(4, "AppDropFiles(hwnd=%Xh, hdrop=%Xh)--cFiles=%u", hwnd, hdrop, cFiles);
  1562.  
  1563.     //
  1564.     //  step through each file and stop on the one the user wants or
  1565.     //  the last file (whichever comes first).
  1566.     //
  1567.     for (u = 0; u < cFiles; u++)
  1568.     {
  1569.         //
  1570.         //  get the next file name and try to open it--if not a valid
  1571.         //  file, then skip to the next one (if there is one).
  1572.         //
  1573.         DragQueryFile(hdrop, u, szFilePath, SIZEOF(szFilePath));
  1574.  
  1575.  
  1576.         //
  1577.         //  !!! destructive !!!
  1578.         //
  1579.         //  attempt to open the file
  1580.         //
  1581.         lstrcpy(gaafd.szFilePath, szFilePath);
  1582.         lstrcpy(gaafd.szFileTitle, gszNull);
  1583.  
  1584.         f = AcmAppFileOpen(hwnd, &gaafd);
  1585.         if (!f)
  1586.         {
  1587.             continue;
  1588.         }
  1589.  
  1590.         AppTitle(hwnd, gaafd.szFileTitle);
  1591.         AcmAppDisplayFileProperties(hwnd, &gaafd);
  1592.  
  1593.         //
  1594.         //  if this is NOT the last file in the list of files that are
  1595.         //  being dropped on us, then bring up a box asking if we should
  1596.         //  continue or stop where we are..
  1597.         //
  1598.         if ((cFiles - 1) != u)
  1599.         {
  1600.             n = DialogBoxParam(ghinst,
  1601.                                DLG_AADRAGDROP,
  1602.                                hwnd,
  1603.                                AcmAppDlgProcDragDropContinue,
  1604.                                MAKELPARAM((WORD)(u + 1), (WORD)cFiles));
  1605.             if (IDCANCEL == n)
  1606.                 break;
  1607.         }
  1608.     }
  1609.  
  1610.     //
  1611.     //  tell the shell to release the memory it allocated for beaming
  1612.     //  the file name(s) over to us... return 0 to show we processed
  1613.     //  the message.
  1614.     //
  1615. App_Drop_Files_Exit:
  1616.  
  1617.     DragFinish(hdrop);
  1618.     return (0L);
  1619. } // AppDropFiles()
  1620.  
  1621.  
  1622. //--------------------------------------------------------------------------;
  1623. //
  1624. //  LRESULT AppSize
  1625. //
  1626. //  Description:
  1627. //      This function handles the WM_SIZE message for the application's
  1628. //      window. This message is sent to the application window after the
  1629. //      size has changed (but before it is painted).
  1630. //
  1631. //  Arguments:
  1632. //      HWND hwnd: Handle to window that generated the WM_SIZE message.
  1633. //
  1634. //      UINT fuSizeType: Specifies the type of resizing requested. This
  1635. //      argument is one of the following: SIZE_MAXIMIZED, SIZE_MINIMIZED,
  1636. //      SIZE_RESTORED, SIZE_MAXHIDE, or SIZE_MAXSHOW.
  1637. //
  1638. //      int nWidth: Width of the new client area for the window.
  1639. //
  1640. //      int nHeight: Height of the new client area for the window.
  1641. //
  1642. //  Return (LRESULT):
  1643. //      Returns zero if the application processes the message.
  1644. //
  1645. //--------------------------------------------------------------------------;
  1646.  
  1647. LRESULT FNLOCAL AppSize
  1648. (
  1649.     HWND                    hwnd,
  1650.     UINT                    fuSizeType,
  1651.     int                     nWidth,
  1652.     int                     nHeight
  1653. )
  1654. {
  1655.     HWND                hedit;
  1656.     RECT                rc;
  1657.  
  1658.     DPF(4, "AppSize(hwnd=%Xh, fuSizeType=%u, nWidth=%d, nHeight=%d)",
  1659.             hwnd, fuSizeType, nWidth, nHeight);
  1660.  
  1661.     //
  1662.     //  unless this application is the one being resized then don't waste
  1663.     //  time computing stuff that doesn't matter. this applies to being
  1664.     //  minimized also because this application does not have a custom
  1665.     //  minimized state.
  1666.     //
  1667.     if ((SIZE_RESTORED != fuSizeType) && (SIZE_MAXIMIZED != fuSizeType))
  1668.         return (0L);
  1669.  
  1670.  
  1671.     //
  1672.     //
  1673.     //
  1674.     GetClientRect(hwnd, &rc);
  1675.     InflateRect(&rc, 1, 1);
  1676.  
  1677.     hedit = GetDlgItem(hwnd, IDD_ACMAPP_EDIT_DISPLAY);
  1678.     SetWindowPos(hedit,
  1679.                  NULL,
  1680.                  rc.left,
  1681.                  rc.top,
  1682.                  rc.right - rc.left,
  1683.                  rc.bottom - rc.top,
  1684.                  SWP_NOZORDER);
  1685.  
  1686.  
  1687.     //
  1688.     //  we processed the message..
  1689.     //
  1690.     return (0L);
  1691. } // AppSize()
  1692.  
  1693.  
  1694. //--------------------------------------------------------------------------;
  1695. //  
  1696. //  LRESULT AcmAppNotify
  1697. //  
  1698. //  Description:
  1699. //  
  1700. //  
  1701. //  Arguments:
  1702. //  
  1703. //  Return (LRESULT):
  1704. //  
  1705. //  
  1706. //--------------------------------------------------------------------------;
  1707.  
  1708. LRESULT FNLOCAL AcmAppNotify
  1709. (
  1710.     HWND                hwnd,
  1711.     WPARAM              wParam,
  1712.     LPARAM              lParam
  1713. )
  1714. {
  1715.     HWND                hwndNext;
  1716.  
  1717.     DPF(1, "AcmAppNotify: hwnd=%.04Xh, wParam=%.04Xh, lParam2=%.08lXh",
  1718.         hwnd, wParam, lParam);
  1719.  
  1720.     //
  1721.     //
  1722.     //
  1723.     hwndNext = GetWindow(hwnd, GW_HWNDFIRST);
  1724.     while (NULL != hwndNext)
  1725.     {
  1726.         if (GetParent(hwndNext) == hwnd)
  1727.         {
  1728.             SendMessage(hwndNext, WM_ACMAPP_ACM_NOTIFY, wParam, lParam);
  1729.         }
  1730.  
  1731.         hwndNext = GetWindow(hwndNext, GW_HWNDNEXT);
  1732.     }
  1733.  
  1734.  
  1735.     //
  1736.     //  now force an update to our display in case driver [dis/en]able
  1737.     //  changed what is playable/recordable.
  1738.     //
  1739.     AcmAppDisplayFileProperties(hwnd, &gaafd);
  1740.  
  1741.  
  1742.     //
  1743.     //
  1744.     //
  1745.     return (1L);
  1746. } // AcmAppNotify()
  1747.  
  1748.  
  1749. //--------------------------------------------------------------------------;
  1750. //
  1751. //  LRESULT AppWndProc
  1752. //
  1753. //  Description:
  1754. //      This is the main application window procedure.
  1755. //
  1756. //  Arguments:
  1757. //      HWND hwnd: Handle to window.
  1758. //
  1759. //      UINT uMsg: Message being sent to the window.
  1760. //
  1761. //      WPARAM wParam: Specific argument to message.
  1762. //
  1763. //      LPARAM lParam: Specific argument to message.
  1764. //
  1765. //  Return (LRESULT):
  1766. //      The return value depends on the message that is being processed.
  1767. //
  1768. //--------------------------------------------------------------------------;
  1769.  
  1770. LRESULT FNEXPORT AppWndProc
  1771. (
  1772.     HWND                    hwnd,
  1773.     UINT                    uMsg,
  1774.     WPARAM                  wParam,
  1775.     LPARAM                  lParam
  1776. )
  1777. {
  1778.     LRESULT             lr;
  1779.  
  1780.     switch (uMsg)
  1781.     {
  1782.         case WM_CREATE:
  1783.             lr = HANDLE_WM_CREATE(hwnd, wParam, lParam, AppCreate);
  1784.             return (lr);
  1785.  
  1786.         case WM_WININICHANGE:
  1787.             HANDLE_WM_WININICHANGE(hwnd, wParam, lParam, AppWinIniChange);
  1788.             return (0L);
  1789.  
  1790.         case WM_INITMENUPOPUP:
  1791.             HANDLE_WM_INITMENUPOPUP(hwnd, wParam, lParam, AppInitMenuPopup);
  1792.             return (0L);
  1793.  
  1794.         case WM_COMMAND:
  1795.             lr = HANDLE_WM_COMMAND(hwnd, wParam, lParam, AppCommand);
  1796.             return (lr);
  1797.  
  1798.         case WM_DROPFILES:
  1799.             //
  1800.             //  some windowsx.h files have a screwed up message cracker for
  1801.             //  WM_DROPFILES. because this is a sample app, i don't want
  1802.             //  people having trouble with bogus windowsx.h files, so crack
  1803.             //  the message manually... you should use the message cracker
  1804.             //  if you know your windowsx.h file is good.
  1805.             //
  1806.             //  lr = HANDLE_WM_DROPFILES(hwnd, wParam, lParam, AppDropFiles);
  1807.             //
  1808.             lr = AppDropFiles(hwnd, (HDROP)wParam);
  1809.             return (lr);
  1810.  
  1811.         case WM_SIZE:
  1812.             //
  1813.             //  handle what we want for sizing, and then always call the
  1814.             //  default handler...
  1815.             //
  1816.             HANDLE_WM_SIZE(hwnd, wParam, lParam, AppSize);
  1817.             break;
  1818.  
  1819.         case WM_QUERYENDSESSION:
  1820.             lr = HANDLE_WM_QUERYENDSESSION(hwnd, wParam, lParam, AppQueryEndSession);
  1821.             return (lr);
  1822.  
  1823.         case WM_ENDSESSION:
  1824.             HANDLE_WM_ENDSESSION(hwnd, wParam, lParam, AppEndSession);
  1825.             return (0L);
  1826.  
  1827.         case WM_CLOSE:
  1828.             HANDLE_WM_CLOSE(hwnd, wParam, lParam, AppClose);
  1829.             return (0L);
  1830.  
  1831.         case WM_DESTROY:
  1832.             PostQuitMessage(0);
  1833.             return (0L);
  1834.  
  1835.         case WM_ACMAPP_ACM_NOTIFY:
  1836.             AcmAppNotify(hwnd, wParam, lParam);
  1837.             return (0L);
  1838.     }
  1839.  
  1840.     return (DefWindowProc(hwnd, uMsg, wParam, lParam));
  1841. } // AppWndProc()
  1842.  
  1843.  
  1844. //==========================================================================;
  1845. //
  1846. //  Main entry and message dispatching code
  1847. //
  1848. //
  1849. //==========================================================================;
  1850.  
  1851. //--------------------------------------------------------------------------;
  1852. //
  1853. //  int WinMain
  1854. //
  1855. //  Description:
  1856. //      This function is called by the system as the initial entry point
  1857. //      for a Windows application.
  1858. //
  1859. //  Arguments:
  1860. //      HINSTANCE hinst: Identifies the current instance of the
  1861. //      application.
  1862. //
  1863. //      HINSTANCE hinstPrev: Identifies the previous instance of the
  1864. //      application (NULL if first instance). For Win 32, this argument
  1865. //      is _always_ NULL.
  1866. //
  1867. //      LPSTR pszCmdLine: Points to null-terminated unparsed command line.
  1868. //      This string is strictly ANSI regardless of whether the application
  1869. //      is built for Unicode. To get the Unicode equivalent call the
  1870. //      GetCommandLine() function (Win 32 only).
  1871. //
  1872. //      int nCmdShow: How the main window for the application is to be
  1873. //      shown by default.
  1874. //
  1875. //  Return (int):
  1876. //      Returns result from WM_QUIT message (in wParam of MSG structure) if
  1877. //      the application is able to enter its message loop. Returns 0 if
  1878. //      the application is not able to enter its message loop.
  1879. //
  1880. //--------------------------------------------------------------------------;
  1881.  
  1882. int PASCAL WinMain
  1883. (
  1884.     HINSTANCE               hinst,
  1885.     HINSTANCE               hinstPrev,
  1886.     LPSTR                   pszCmdLine,
  1887.     int                     nCmdShow
  1888. )
  1889. {
  1890.     int                 nResult;
  1891.     HWND                hwnd;
  1892.     MSG                 msg;
  1893.     HACCEL              haccl;
  1894.  
  1895.     DbgInitialize(TRUE);
  1896.  
  1897.     //
  1898.     //  our documentation states that WinMain is supposed to return 0 if
  1899.     //  we do not enter our message loop--so assume the worst...
  1900.     //
  1901.     nResult = 0;
  1902.  
  1903.     //
  1904.     //  make our instance handle global for convenience..
  1905.     //
  1906.     ghinst = hinst;
  1907.  
  1908.     //
  1909.     //  init some stuff, create window, etc.. note the explicit cast of
  1910.     //  pszCmdLine--this is to mute a warning (and an ugly ifdef) when
  1911.     //  compiling for Unicode. see AppInit() for more details.
  1912.     //
  1913.     hwnd = AppInit(hinst, hinstPrev, (LPTSTR)pszCmdLine, nCmdShow);
  1914.     if (hwnd)
  1915.     {
  1916.         haccl = LoadAccelerators(hinst, ACCEL_APP);
  1917.  
  1918.         //
  1919.         //  dispatch messages
  1920.         //
  1921.         while (GetMessage(&msg, NULL, 0, 0))
  1922.         {
  1923.             //
  1924.             //  do all the special stuff required for this application
  1925.             //  when dispatching messages..
  1926.             //
  1927.             if (!TranslateAccelerator(hwnd, haccl, &msg))
  1928.             {
  1929.                 TranslateMessage(&msg);
  1930.                 DispatchMessage(&msg);
  1931.             }
  1932.         }
  1933.  
  1934.         //
  1935.         //  return result of WM_QUIT message.
  1936.         //
  1937.         nResult = (int)msg.wParam;
  1938.     }
  1939.  
  1940.     //
  1941.     //  shut things down, clean up, etc.
  1942.     //
  1943.     nResult = AppExit(hinst, nResult);
  1944.  
  1945.     return (nResult);
  1946. } // WinMain()
  1947.